package com.wxxymaker.service.impl;

import com.wxxymaker.model.dao.StageCountDao;
import com.wxxymaker.model.entity.Shop;
import com.wxxymaker.model.entity.Stage;
import com.wxxymaker.model.entity.StageCount;
import com.wxxymaker.service.ShopService;
import com.wxxymaker.service.StageCountService;
import com.wxxymaker.service.StageService;
import com.wxxymaker.utils.web.StageCountUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

/**
 * @Author: Soft
 * @Date: 2018/5/11 1:10
 * @Desc: 阶段统计业务层
 */
@Service("stageCountService")
public class StageCountServiceImpl implements StageCountService {
    private static Logger log = LoggerFactory.getLogger(StageCountServiceImpl.class);

    private final ShopService shopService;

    private final StageService stageService;

    private final StageCountDao dao;

    @Autowired
    public StageCountServiceImpl(StageCountDao dao, StageService stageService, ShopService shopService) {
        this.dao = dao;
        this.stageService = stageService;
        this.shopService = shopService;
    }

    @Override
    @Transactional
    public StageCount add(StageCount stageCount) {
        stageCount.setCountTime(new Date());
        // stageCount.setStageName(stageCount.getStage().getName());
        // 避免出现NaN或无穷大
        if (Double.isNaN(stageCount.getTotal()) || Double.isInfinite(stageCount.getTotal())) {
            stageCount.setTotal(0.0);
        }
        if (Double.isNaN(stageCount.getRate()) || Double.isInfinite(stageCount.getRate())) {
            stageCount.setRate(0.0);
        }

        StageCount exist = this.isExist(stageCount.getStage(), stageCount.getShop());
        if (exist != null) {
            stageCount.setId(exist.getId());
        }
        return dao.saveAndFlush(stageCount);
    }

    @Override
    @Transactional
    public StageCount delete(Integer id) {
        StageCount one = dao.findOne(id);
        if (null != one) {
            dao.delete(one);
        }
        return one;
    }

    @Override
    @Transactional
    public int deleteByStage(Stage stage) {
        return dao.deleteByStage(stage);
    }

    @Override
    public Page<StageCount> page(Integer pageNo, Integer size, Map<String, Object> map) {
        return this.page(pageNo, size, map, new Sort(Sort.Direction.DESC, "countTime"));
    }

    @Override
    public Page<StageCount> page(Integer pageNo, Integer size, Map<String, Object> map, Sort sort) {
        Specification<StageCount> specification = new Specification<StageCount>() {
            @Override
            public Predicate toPredicate(Root<StageCount> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                if (map == null)
                    return null;
                List<Predicate> ps = new LinkedList<>();
                map.forEach((k, v)->{
                    if (!"".equals(v)) {
                        switch (k){
                            case "shop_id":
                                ps.add(cb.equal(root.get("shop").get("id"), v));
                                break;
                            case "stage_id":
                                ps.add(cb.equal(root.get("stage").get("id"), v));
                                break;
                            default:
                                ps.add(cb.equal(root.get(k), v));
                                break;
                        }
                    }
                });
                query.where(ps.toArray(new Predicate[ps.size()]));
                return null;
            }
        };
        Pageable pageable = new PageRequest(pageNo - 1, size, sort);
        return dao.findAll(specification, pageable);
    }

    @Override
    public Page<StageCount> page(Integer pageNo, Integer size) {
        return null;
    }

    @Override
    public List<StageCount> findAllByShop(Shop shop) {
        return dao.findAllByShop(shop);
    }

    @Override
    public StageCount isExist(Stage stage, Shop shop) {
        return dao.findByStageAndShop(stage, shop);
    }

    @Override
    @Async
    public void countScoreAndSave(Stage stage) {
        // 获取该阶段下所有公司
        List<Shop> shops = stageService.getShops(stage);

        for (Shop shop : shops) {
            // 获取该阶段下某个公司的各种等级评价的人数
            long[] longs = stageService.countStarNumForShop(stage, shop);
            // 计算总评分
            StageCountUtil.CountResult result = StageCountUtil.countScore(longs[0], longs[1], longs[2], longs[3]);
            StageCount stageCount = new StageCount();
            stageCount.setStage(stage);
            stageCount.setShop(shop);
            stageCount.setTotal(result.getTotal());
            stageCount.setCancel(result.isCancel());
            stageCount.setRate((result.getTotal() - shop.getPrevTotal()) / shop.getPrevTotal());
            if (this.add(stageCount) != null) {
                // 设置公司总评和记录当前阶段总评
                double v = this.countTotalForShop(shop);
                shopService.setTotalAndPrev(shop, stageCount.getTotal(), v);
            }
        }
    }

    @Override
    public double countTotalForShop(Shop shop) {
        try {
            return dao.shopAvgTotal(shop.getId());
        } catch (Exception e) {
            log.error("{}", e.getMessage());
            return 0.0;
        }
    }
}
